using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.Common;
using Microsoft.CodeAnalysis.Common.Semantics;
using Microsoft.CodeAnalysis.Common.Symbols;
using Microsoft.CodeAnalysis.CSharp.Semantics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp
{
#if REMOVE
    /// <summary>
    /// Represents a token in the syntax tree.
    /// </summary>
    [DebuggerDisplay("{DebuggerDisplay,nq}")]
    public struct SyntaxToken : IEquatable<SyntaxToken>
    {
        internal static readonly Func<SyntaxToken, bool> Any = t => true;
        internal static readonly Func<SyntaxToken, bool> NonZeroWidth = t => t.Width > 0;

        private readonly CSharpSyntaxNode parent;
        private readonly Syntax.InternalSyntax.SyntaxToken node;
        private readonly int position;
        private readonly int index;

        internal SyntaxToken(CSharpSyntaxNode parent, Syntax.InternalSyntax.SyntaxToken node, int position, int index)
        {
            Debug.Assert(parent == null || parent.Kind != SyntaxKind.List);
            Debug.Assert(node != null || (position == 0 && index == 0 && parent == null));
            Debug.Assert(position >= 0);

            this.position = position;
            this.parent = parent;
            this.node = node;
            this.index = index;

#if DEBUG
            if (parent != null && node != null)
            {
                var nodeOrToken = ChildSyntaxList.ItemInternal(parent, index, fromTokenCtor: true);

                Debug.Assert(nodeOrToken.UnderlyingNode == node, "node was not found at given index");
                Debug.Assert(nodeOrToken.Position == position, "position mismatch");
            }
            else
            {
                Debug.Assert(parent == null || position >= parent.Position);
            }
#endif
        }

        internal string DebuggerDisplay
        {
            get
            {
                return GetType().Name + " " + CSharpKind() + " " + ToString();
            }
        }

        internal Syntax.InternalSyntax.SyntaxToken Node
        {
            get
            {
                return this.node;
            }
        }

        internal int Offset
        {
            get
            {
                return parent != null ? position - parent.Position : position;
            }
        }

        internal int Index
        {
            get
            {
                return this.index;
            }
        }

        internal int Position
        {
            get
            {
                return position;
            }
        }

        internal int End
        {
            get
            {
                return position + FullWidth;
            }
        }

        // Gets start of the span without creating actual span
        public int SpanStart
        {
            get
            {
                if (node != null)
                {
                    return position + node.LeadingWidth;
                }

                return position;
            }
        }

        /// <summary>
        /// The token's <see cref="SyntaxKind"/>.
        /// </summary>
        public SyntaxKind CSharpKind()
        {
            return this.node != null ? this.node.Kind : SyntaxKind.None;
        }

        /// <summary>
        /// The language name that this token is syntax of.
        /// </summary>
        public string Language
        {
            get { return LanguageNames.CSharp; }
        }

        /// <summary>
        /// The kind of token, given its position in the syntax. This differs from <see
        /// cref="CSharpKind()"/> when a contextual keyword is used in a place in the syntax that gives it
        /// its keyword meaning.
        /// </summary>
        /// <remarks>
        /// The ContextualKind is relevant only on contextual keyword tokens. ContextualKind differs
        /// from Kind when a token is used in context where the token should be interpreted as a
        /// keyword.
        /// </remarks>
        internal SyntaxKind CSharpContextualKind()
        {
            return this.node != null ? this.node.ContextualKind : SyntaxKind.None;
        }

        /// <summary>
        /// Determines whether the node represents a language construct that was actually parsed
        /// from the source code. Missing nodes are generated by the parser in error scenarios to
        /// represent constructs that should have been present in the source code in order to
        /// compile successfully but were actually missing.
        /// </summary>
        public bool IsMissing
        {
            get
            {
                return this.node != null && this.node.IsMissing;
            }
        }

        /// <summary>
        /// The text of the token as it appeared in the source.
        /// </summary>
        internal string Text
        {
            get
            {
                return this.node != null ? this.node.Text : string.Empty;
            }
        }

        /// <summary>
        /// The value designated by the token, if it is a literal (e.g. true, false, 12, "foo").  For
        /// example, the sequence of letters of an identifier, excluding the escape character if it
        /// was escaped in the source, or the characters of a string excluding the quotes and with
        /// escape sequences translated.  For constants, ValueText is the canonical form of the
        /// designated value (e.g. leading zeroes are dropped).
        /// </summary>
        public object Value
        {
            get
            {
                return this.node != null
                    ? this.node.Value
                    : null;
            }
        }

        /// <summary>
        /// The string text of the value of the token.  For example, the sequence of letters of an
        /// identifier, excluding the escape character if it was escaped in the source, or the
        /// characters of a string excluding the quotes and with escape sequences translated.  For
        /// constants, ValueText is the canonical form of the designated value (e.g. leading zeroes
        /// are dropped).
        /// </summary>
        public string ValueText
        {
            get
            {
                return this.node != null
                    ? this.node.ValueText
                    : string.Empty;
            }
        }

        /// <summary>
        /// The immediately enclosing <see cref="CSharpSyntaxNode"/>.
        /// </summary>
        public CSharpSyntaxNode Parent
        {
            get
            {
                return this.parent;
            }
        }

        /// <summary>
        /// SyntaxTree which contains current SyntaxToken.
        /// </summary>
        public CSharpSyntaxTree SyntaxTree
        {
            get
            {
                var parent = this.parent;
                return parent == null ? null : parent.SyntaxTree;
            }
        }

        /// <summary>
        /// The absolute span of characters of the token, including surrounding trivia that is
        /// attached to the token.
        /// </summary>
        public TextSpan FullSpan
        {
            get
            {
                return new TextSpan(position, FullWidth);
            }
        }

        /// <summary>
        /// The span of characters of the token, excluding trivia surrounding the token.
        /// </summary>
        public TextSpan Span
        {
            get
            {
                return this.node != null
                    ? new TextSpan(position + this.node.LeadingWidth, this.node.Width)
                    : new TextSpan(position, 0);
            }
        }

        /// <summary>
        /// The full width of the token, including surrounding trivia that is attached to the token.
        /// </summary>
        internal int FullWidth
        {
            get
            {
                return this.node != null
                    ? this.node.FullWidth
                    : 0;
            }
        }

        /// <summary>
        /// The width of the token, excluding trivia surrounding the token.
        /// </summary>
        internal int Width
        {
            get
            {
                return this.node != null
                    ? this.node.Width
                    : 0;
            }
        }

        /// <summary>
        /// The width of trivia attached to and preceding the token.
        /// </summary>
        internal int LeadingWidth
        {
            get
            {
                return this.node != null
                    ? this.node.LeadingWidth
                    : 0;
            }
        }

        /// <summary>
        /// The width of trivia attached to and following the token.
        /// </summary>
        internal int TrailingWidth
        {
            get
            {
                return this.node != null
                    ? this.node.TrailingWidth
                    : 0;
            }
        }

        /// <summary>
        /// True if any diagnostics are associated with the token in the context of its parse tree.
        /// </summary>
        public bool ContainsDiagnostics
        {
            get
            {
                return this.node != null && this.node.ContainsDiagnostics;
            }
        }

        /// <summary>
        /// Determines whether this token or any of its trivia has annotations.
        /// </summary>
        public bool ContainsAnnotations
        {
            get
            {
                return this.node != null && this.node.ContainsAnnotations;
            }
        }

        /// <summary>
        /// Determines whether this token has annotations of the specified type.
        /// </summary>
        public bool HasAnnotations(Type annotationType)
        {
            return this.node != null && this.node.HasAnnotations(annotationType);
        }

        /// <summary>
        /// Determines whether this token has the specific annotation.
        /// </summary>
        public bool HasAnnotation(SyntaxAnnotation annotation)
        {
            return this.node != null && this.node.HasAnnotation(annotation);
        }

        /// <summary>
        /// Gets all annotations of the specified type attached to this token.
        /// </summary>
        public IEnumerable<SyntaxAnnotation> GetAnnotations(Type annotationType)
        {
            SyntaxAnnotation.CheckTypeIsSubclassOfSyntaxAnnotation(annotationType);
            return this.node == null
                ? SpecializedCollections.EmptyEnumerable<SyntaxAnnotation>()
                : this.node.GetAnnotations(annotationType);
        }

        /// <summary>
        /// True if any directives are associated with the token in the context of its parse tree.
        /// </summary>
        public bool ContainsDirectives
        {
            get
            {
                return this.node != null && this.node.ContainsDirectives;
            }
        }

        /// <summary>
        /// True if any trivia of this token is structured.
        /// </summary>
        internal bool HasStructuredTrivia
        {
            get
            {
                return this.node != null && this.node.HasStructuredTrivia;
            }
        }

        /// <summary>
        /// Returns the string representation of this token, not including its leading and trailing trivia.
        /// </summary>
        /// <returns>The string representation of this token, not including its leading and trailing trivia.</returns>
        /// <remarks>The length of the returned string is always the same as Span.Length</remarks>
        public override string ToString()
        {
            return this.node != null ? this.node.ToString() : string.Empty;
        }

        /// <summary>
        /// Returns the full string representation of this token including its leading and trailing trivia.
        /// </summary>
        /// <returns>The full string representation of this token including its leading and trailing trivia.</returns>
        /// <remarks>The length of the returned string is always the same as FullSpan.Length</remarks>
        public string ToFullString()
        {
            return this.node != null ? this.node.ToFullString() : string.Empty;
        }

        /// <summary>
        /// Writes the full text of this token to the specified TextWriter.
        /// </summary>
        public void WriteTo(System.IO.TextWriter writer)
        {
            if (this.node != null)
            {
                this.node.WriteTo(writer, true, true);
            }
        }

        /// <summary>
        /// Writes the text of this token to the specified TextWriter, optionally including trivia.
        /// </summary>
        internal void WriteTo(System.IO.TextWriter writer, bool leading, bool trailing)
        {
            if (this.node != null)
            {
                this.node.WriteTo(writer, leading, trailing);
            }
        }

        /// <summary>
        /// True if the token has preceding trivia that is attached to the token.
        /// </summary>
        public bool HasLeadingTrivia
        {
            get { return this.node != null && this.node.GetLeadingTrivia() != null; }
        }

        /// <summary>
        /// The list of trivia that precedes and is attached to the token.
        /// </summary>
        public SyntaxTriviaList LeadingTrivia
        {
            get
            {
                return this.node != null
                    ? new SyntaxTriviaList(this, this.node.GetLeadingTrivia())
                    : default(SyntaxTriviaList);
            }
        }

        /// <summary>
        /// True if the token has trailing trivia that is attached to the token.
        /// </summary>
        public bool HasTrailingTrivia
        {
            get { return this.node != null && this.node.GetTrailingTrivia() != null; }
        }

        /// <summary>
        /// The list of trivia that follows and is attached to the token.
        /// </summary>
        public SyntaxTriviaList TrailingTrivia
        {
            get
            {
                if (this.node != null)
                {
                    var leading = this.node.GetLeadingTrivia();
                    var trailing = this.node.GetTrailingTrivia();
                    if (leading == null)
                    {
                        return new SyntaxTriviaList(this, trailing, this.position + this.node.Width, index: 0);
                    }
                    else
                    {
                        var index = leading.IsList ? leading.SlotCount : 1;
                        return new SyntaxTriviaList(this, trailing, this.position + leading.FullWidth + this.node.Width, index);
                    }
                }

                return default(SyntaxTriviaList);
            }
        }

        /// <summary>
        /// Gets a list of both leading and trailing trivia for the token.
        /// </summary>
        public IEnumerable<SyntaxTrivia> GetAllTrivia()
        {
            if (this.HasLeadingTrivia)
            {
                if (this.HasTrailingTrivia)
                {
                    return this.LeadingTrivia.Concat(this.TrailingTrivia);
                }

                return this.LeadingTrivia;
            }
            else if (this.HasTrailingTrivia)
            {
                return this.TrailingTrivia;
            }
            else
            {
                return SpecializedCollections.EmptyEnumerable<SyntaxTrivia>();
            }
        }

        /// <summary>
        /// Clones the token and adds the <paramref name="trivia"/> as leading trivia.
        /// </summary>
        /// <param name="trivia">The <see cref="SyntaxTriviaList"/> to add as leading trivia.</param>
        /// <returns>A new token with leading trivia.</returns>
        public SyntaxToken WithLeadingTrivia(SyntaxTriviaList trivia)
        {
            return this.node != null
                ? new SyntaxToken(null, this.node.WithLeadingTrivia((Syntax.InternalSyntax.CSharpSyntaxNode)trivia.Node), position: 0, index: 0)
                : default(SyntaxToken);
        }

        /// <summary>
        /// Clones the token and adds the <paramref name="trivia"/> as trailing trivia.
        /// </summary>
        /// <param name="trivia">The <see cref="SyntaxTriviaList"/> to add as trailing trivia.</param>
        /// <returns>A new token with trailing trivia.</returns>
        public SyntaxToken WithTrailingTrivia(SyntaxTriviaList trivia)
        {
            return this.node != null
                ? new SyntaxToken(null, this.node.WithTrailingTrivia((Syntax.InternalSyntax.CSharpSyntaxNode)trivia.Node), position: 0, index: 0)
                : default(SyntaxToken);
        }

        public SyntaxToken WithLeadingTrivia(params SyntaxTrivia[] trivia)
        {
            return this.WithLeadingTrivia((IEnumerable<SyntaxTrivia>)trivia);
        }

        public SyntaxToken WithLeadingTrivia(IEnumerable<SyntaxTrivia> trivia)
        {
            return this.WithLeadingTrivia(trivia.ToSyntaxTriviaList());
        }

        public SyntaxToken WithTrailingTrivia(params SyntaxTrivia[] trivia)
        {
            return this.WithTrailingTrivia((IEnumerable<SyntaxTrivia>)trivia);
        }

        public SyntaxToken WithTrailingTrivia(IEnumerable<SyntaxTrivia> trivia)
        {
            return this.WithTrailingTrivia(trivia.ToSyntaxTriviaList());
        }

        /// <summary>
        /// Returns true if <paramref name="left"/> equals <paramref name="right"/>.
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        public static bool operator ==(SyntaxToken left, SyntaxToken right)
        {
            return left.Equals(right);
        }

        /// <summary>
        /// Returns true if <paramref name="left"/> is not equal to <paramref name="right"/>.
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        public static bool operator !=(SyntaxToken left, SyntaxToken right)
        {
            return !left.Equals(right);
        }

        /// <summary>
        /// Returns true if this <see cref="SyntaxToken"/> equals <paramref name="other"/>.
        /// </summary>
        public bool Equals(SyntaxToken other)
        {
            // index replaces position to ensure equality.  Assert if position affects equality.
            Debug.Assert(
                (this.parent == other.parent && this.node == other.node && this.position == other.position && this.index == other.index) ==
                (this.parent == other.parent && this.node == other.node && this.index == other.index));

            return this.node == other.node && 
                   this.parent == other.parent &&
                   this.index == other.index;
        }

        /// <summary>
        /// Returns true if this <see cref="SyntaxToken"/> equals <paramref name="obj"/>.
        /// </summary>
        public override bool Equals(object obj)
        {
            return obj is SyntaxToken && Equals((SyntaxToken)obj);
        }

        /// <summary>
        /// True is <paramref name="other"/> is equivalent to this <see cref="SyntaxToken"/>.  Two tokens are equivalent
        /// if they are the same kind, have the same text and have the same full width.
        /// </summary>
        public bool IsEquivalentTo(SyntaxToken other)
        {
            if (this.node == null || other.node == null)
            {
                return this.node == null && other.node == null;
            }
            else
            {
                return this.node.IsEquivalentTo(other.node);
            }
        }

        /// <summary>
        /// Serves as a hash function for the <see cref="SyntaxToken"/>
        /// </summary>
        public override int GetHashCode()
        {
            return unchecked(
                (this.parent != null ? this.parent.GetHashCode() : 0)
                + (this.node != null ? this.node.GetHashCode() : 0)
                + this.index);
        }

        /// <summary>
        /// Converts a <see cref="SyntaxToken"/> to a <see cref="SyntaxToken"/>
        /// </summary>
        public static implicit operator SyntaxToken(SyntaxToken token)
        {
            return new SyntaxToken(token.parent, token.node, token.Position, token.index);
        }

        /// <summary>
        /// Converts a <see cref="SyntaxToken"/> to a <see cref="SyntaxToken"/>
        /// </summary>
        public static explicit operator SyntaxToken(SyntaxToken token)
        {
            return new SyntaxToken((CSharpSyntaxNode)token.Parent, (Syntax.InternalSyntax.SyntaxToken)token.Node, token.Position, token.Index);
        }

        /// <summary>
        /// Converts a <see cref="SyntaxToken"/> to a <see cref="SyntaxNodeOrToken"/>
        /// </summary>
        public static implicit operator SyntaxNodeOrToken(SyntaxToken token)
        {
            return (SyntaxToken)token;
        }

        /// <summary>
        /// Converts a <see cref="SyntaxNodeOrToken"/> to a <see cref="SyntaxToken"/>
        /// </summary>
        public static explicit operator SyntaxToken(SyntaxNodeOrToken nodeOrToken)
        {
            return (SyntaxToken)(SyntaxToken)nodeOrToken;
        }

        /// <summary>
        /// Adds this annotation to a given syntax token, creating a new syntax token of the same type with the
        /// annotation on it.
        /// </summary>
        public SyntaxToken WithAdditionalAnnotations(params SyntaxAnnotation[] annotations)
        {
            return (SyntaxToken)((SyntaxToken)this).WithAdditionalAnnotations(annotations);
        }

        /// <summary>
        /// Removes the annotations from the given syntax token, creating a new syntax token of the same type without
        /// the annotations on it
        /// </summary>
        public SyntaxToken WithoutAnnotations(params SyntaxAnnotation[] annotations)
        {
            return (SyntaxToken)((SyntaxToken)this).WithoutAnnotations(annotations);
        }

        /// <summary>
        /// Copies all SyntaxAnnotations, if any, from this SyntaxToken instance and attaches them to a new instance based on <paramref name="token" />.
        /// </summary>
        /// <remarks>
        /// If no annotations are copied, just returns <paramref name="token" />.
        /// </remarks>
        public SyntaxToken CopyAnnotationsTo(SyntaxToken token)
        {
            return (SyntaxToken)((SyntaxToken)this).CopyAnnotationsTo(token);
        }

        /// <summary>
        /// Gets a <see cref="Location"/> for this token.
        /// </summary>
        public Location GetLocation()
        {
            return new SourceLocation(this);
        }

        /// <summary>
        /// Gets a list of all the diagnostics associated with this token and any related trivia.
        /// This method does not filter diagnostics based on #pragmas and compiler options
        /// like nowarn, warnaserror etc.
        /// </summary>
        public IEnumerable<Diagnostic> GetDiagnostics()
        {
            return this.SyntaxTree.GetDiagnostics(this);
        }

    #region Syntax Navigation

        /// <summary>
        /// Returns the token after this token in the syntax tree.
        /// </summary>
        /// <param name="includeZeroWidth">True if zero width tokens should be included, false by
        /// default.</param>
        /// <param name="includeSkipped">If true then search inside trailing trivia and skipped token trivia may be
        /// returned.</param>
        /// <param name="includeDirectives">If true then search inside trailing trivia and directive trivia may be
        /// returned</param>
        /// <param name="includeDocumentationComments">if true then search inside trailing trivia and document comment
        /// trivia may be returned.</param>
        public SyntaxToken GetNextToken(bool includeZeroWidth = false, bool includeSkipped = false, bool includeDirectives = false, bool includeDocumentationComments = false)
        {
            return (SyntaxToken)SyntaxNavigator.Instance.GetNextToken(this, includeZeroWidth, includeSkipped, includeDirectives, includeDocumentationComments);
        }

        /// <summary>
        /// Returns the token after this token in the syntax tree.
        /// </summary>
        /// <param name="predicate">Delegate applied to each token.  The token is returned if the predicate returns
        /// true.</param>
        /// <param name="stepInto">Delegate applied to trivia.  If this delegate is present then trailing trivia is
        /// included in the search.</param>
        internal SyntaxToken GetNextToken(Func<SyntaxToken, bool> predicate, Func<SyntaxTrivia, bool> stepInto = null)
        {
            return (SyntaxToken)SyntaxNavigator.Instance.GetNextToken(this, SyntaxNavigator.ToCommon(predicate), SyntaxNavigator.ToCommon(stepInto));
        }

        /// <summary>
        /// Returns the token before this token in the syntax tree.
        /// </summary>
        /// <param name="includeZeroWidth">True if zero width tokens should be included, false by
        /// default.</param>
        /// <param name="includeSkipped">If true then search inside leading trivia and skipped token trivia may be
        /// returned.</param>
        /// <param name="includeDirectives">If true then search inside leading trivia and directive trivia may be
        /// returned</param>
        /// <param name="includeDocumentationComments">if true then search inside leading trivia and document comment
        /// trivia may be returned.</param>
        public SyntaxToken GetPreviousToken(bool includeZeroWidth = false, bool includeSkipped = false, bool includeDirectives = false, bool includeDocumentationComments = false)
        {
            return (SyntaxToken)SyntaxNavigator.Instance.GetPreviousToken(this, includeZeroWidth, includeSkipped, includeDirectives, includeDocumentationComments);
        }

        /// <summary>
        /// Returns the token before this token in the syntax tree.
        /// </summary>
        /// <param name="predicate">Delegate applied to each token.  The token is returned if the predicate returns
        /// true.</param>
        /// <param name="stepInto">Delegate applied to trivia.  If this delegate is present then trailing trivia is
        /// included in the search.</param>
        internal SyntaxToken GetPreviousToken(Func<SyntaxToken, bool> predicate, Func<SyntaxTrivia, bool> stepInto = null)
        {
            return (SyntaxToken)SyntaxNavigator.Instance.GetPreviousToken(this, SyntaxNavigator.ToCommon(predicate), SyntaxNavigator.ToCommon(stepInto));
        }

        #endregion

        /// <summary>
        /// Determines if the token is a descendant of a structured trivia.
        /// </summary>
        public bool IsPartOfStructuredTrivia()
        {
            return Parent != null && Parent.IsPartOfStructuredTrivia();
        }

        /// <summary>
        /// Creates a new token with the specified old trivia replaced with computed new trivia.
        /// </summary>
        /// <param name="trivia">The trivia to be replaced; descendants of the root token.</param>
        /// <param name="computeReplacementTrivia">A function that computes a replacement trivia for
        /// the argument trivia. The first argument is the original trivia. The second argument is
        /// the same trivia rewritten with replaced structure.</param>
        public SyntaxToken ReplaceTrivia(IEnumerable<SyntaxTrivia> trivia, Func<SyntaxTrivia, SyntaxTrivia, SyntaxTriviaList> computeReplacementTrivia)
        {
            return SyntaxReplacer.Replace(this, trivia: trivia, computeReplacementTrivia: computeReplacementTrivia);
        }

        /// <summary>
        /// Creates a new token with the specified old trivia replaced with a new trivia. The old trivia may appear in
        /// the token's leading or trailing trivia.
        /// </summary>
        /// <param name="oldTrivia">The trivia to be replaced.</param>
        /// <param name="newTrivia">The new trivia to use in the new tree in place of the old
        /// trivia.</param>
        public SyntaxToken ReplaceTrivia(SyntaxTrivia oldTrivia, SyntaxTriviaList newTrivia)
        {
            return SyntaxReplacer.Replace(this, trivia: new[] { oldTrivia }, computeReplacementTrivia: (o, r) => newTrivia);
        }

        /// <summary>
        /// Creates a new token with all whitespace and end of line trivia replaced with regularly
        /// formatted trivia.
        /// </summary>
        /// <param name="indentation">An optional sequence of whitespace characters that defines a
        /// single level of indentation.</param>
        /// <param name="elasticTrivia">If true the replaced trivia is elastic trivia.</param>
        /// <returns></returns>
        public SyntaxToken NormalizeWhitespace(string indentation = SyntaxExtensions.DefaultIndentation, bool elasticTrivia = false)
        {
            return SyntaxFormatter.Format(this, indentation, elasticTrivia);
        }

        public bool IsKeyword()
        {
            return SyntaxFacts.IsKeywordKind(CSharpKind());
        }

        public bool IsContextualKeyword()
        {
            return SyntaxFacts.IsContextualKeyword(CSharpKind());
        }

        public bool IsReservedKeyword()
        {
            return SyntaxFacts.IsReservedKeyword(CSharpKind());
        }

        public bool IsVerbatimStringLiteral()
        {
            return CSharpKind() == SyntaxKind.StringLiteralToken && Text.Length > 0 && Text[0] == '@';
        }

        public bool IsVerbatimIdentifier()
        {
            return CSharpKind() == SyntaxKind.IdentifierToken && Text.Length > 0 && Text[0] == '@';
        }

        public VarianceKind VarianceKindFromToken()
        {
            switch (CSharpKind())
            {
                case SyntaxKind.OutKeyword: return VarianceKind.Out;
                case SyntaxKind.InKeyword: return VarianceKind.In;
                default: return VarianceKind.None;
            }
        }
    }
#endif
}